# Copyright 2010 Mikko Rantanen
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from time import time
import stat
import os
import re
import errno
import logging
import tempfile
import shutil

import fsentry

cachedir = '/home/wace/.mf'

class File(fsentry.FSEntry):
    """
        Abstract base class for all file-like objects.
        Mainly SFDs and MFD contents.

        Implementations should implement:
        get_fileresource:
            Retrieves the binary resource (object version/file)
            for this object.
    """

    def __init__(self, parent, iteminfo, objver, objfile):
        fsentry.FSEntry.__init__(self, parent, iteminfo)

        self.objver = objver
        self.file = objfile
        self.refcount = 0
        self.filehandle = None

        # Files (MAYBE) have one link.
        # TODO: Check how many links files should have. :P
        self.st_nlink = 1
        self.st_size = self.file['Size']

        # Temporary till we figure out smarter defaults.
        self.st_mode = stat.S_IFREG | 0444
        self.st_ino = 0
        self.st_dev = 0
        self.st_uid = os.getuid()
        self.st_gid = os.getgid()
        self.st_atime = int(time())
        self.st_mtime = self.st_atime
        self.st_ctime = self.st_atime

    def get_file(self):

        cachepath = '%s/file-%s-%s.bin' % (cachedir, self.file['ID'], self.file['Version'])

        if not os.path.isfile(cachepath):
            logging.info('File %s-%s not found from cache, downloading...' %
                         (self.file['ID'], self.file['Version']))

            tfhandle, tfpath = tempfile.mkstemp()
            tf = os.fdopen(tfhandle, 'w+b')
            try:
                self.get_fileresource().get('download', file=tf)
                tf.close()
            except:
                os.remove(tfpath)
                raise

            logging.debug('Moving tempfile %s to %s' % (tfpath, cachepath))
            shutil.move(tfpath, cachepath)

        return file(cachepath)

        
    def get_fileresource(self):
        return self.get_conn().resource(
            'objects/%s/%s/%s/files/%s' % 
            (self.objver['Type'], self.objver['ID'], self.objver['Version'], self.file['ID']))

    def open(self, flags):
        if self.refcount == 0:
            self.filehandle = self.get_file()
            logging.info('%s opened', self.get_fspath())

        self.refcount += 1
        logging.debug('Open references: %s (%s)', (self.refcount, self.get_fspath()))
        return 0

    def read(self, size, offset):
        assert self.refcount > 0, "File isn't open. Cannot read!"

        self.filehandle.seek(offset)
        return self.filehandle.read(size)

    def write(self, buf, offset):
        return -errno.EACCES

    def release(self, flags):
        assert self.refcount > 0, "No reserved handles, cannot release anything"
        
        self.refcount -= 1
        logging.debug('Open references: %s (%s)', (self.refcount, self.get_fspath()))

        if self.refcount == 0:
            self.filehandle.close()
            self.filehandle = None
            logging.info('%s closed', self.get_fspath())
        return 0

